#include <iostream>
#include <cassert>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

#define MAX 1024

using namespace std;

/**
 * 管道的四种情况：
 *   1.管道无数据，读端read阻塞等待，直到写端写入
 *   2.管道被写满，写端write阻塞等待，直到读端读走，已读过的数据允许覆盖
 *   3.写端关闭，读端read直接返回0
 *   4.读端关闭，OS向写端进程发送kill -13信号SIGPIPE，终止进程
 * 管道的五种特性：
 *   1.匿名管道只用于有血缘关系的进程进行通信
 *   2.内核会对管道操作进行同步与互斥
 *   3.管道的生命周期伴随于进程
 *   4.管道读写面向字节流
 *   5.管道为单向通信，特殊的半双工
 */

int main()
{
    //创建管道
    int pipefd[2] = {0};
    int n = pipe(pipefd);
    assert(n == 0);
    cout << "pipefd[0]:" << pipefd[0] << ", pipefd[1]:" << pipefd[1] << endl;

    //创建子进程
    pid_t id = fork();
    if(id < 0) {
        perror("fork"); //意料之外，用if，意料之中，用assert
        return 1;
    }

    //子进程
    if(id == 0) {
        close(pipefd[0]);
        int cnt = 10;
        while(cnt) {
            char message[MAX];
            snprintf(message, sizeof(message)-1, "hello father, I am child, pid:%d, cnt:%d", getpid(), cnt);
            write(pipefd[1], message, strlen(message));
            cnt--;
        }
        exit(0);
    }

    //父进程
    close(pipefd[1]);
    char buffer[MAX];
    while(true) {
        sleep(1);
        ssize_t n = read(pipefd[0], buffer, sizeof(buffer)-1); //-1给\0留出空间
        if(n > 0) {
            buffer[n] = '\0';
            cout << getpid() << ": child say \"" << buffer << "\" to me!" << endl;
        } else if(n == 0) {
            cout << "child quit, me too!" << endl;
            break;
        }
    }

    //回收子进程
    pid_t rid = waitpid(id, nullptr, 0);
    if(rid == id) {
        cout << "wait success" << endl;
    }

    return 0;
}